from typing import Dict

import pandas as pd

from Processor.SignalProcessor import SignalProcessor
from model.FaultDetectionResult import FaultTypeResult
from model.FaultType import FaultType
from utils import compute_magnitude_dft, compute_angle_dft, extract_channel_columns


class FaultTypeDetector:
    """故障类型检测器"""

    def __init__(self):
        self.processor = SignalProcessor()

    def detect(self, df: pd.DataFrame, t_fault: pd.Timestamp, cfg_obj) -> FaultTypeResult:
        """故障类型检测"""

        channels = extract_channel_columns(df)

        # Step 2: 获取故障前后的数据窗口
        try:
            fault_idx = df.index.get_indexer([t_fault], method="nearest")[0]
        except KeyError:
            return FaultTypeResult(
                fault_type=FaultType.UNKNOWN,
                details={"error": "故障时间不在录波范围内"}
            )

        window = int(cfg_obj.sample_rates[0] // cfg_obj.reference_frequency)

        # 故障前窗口：预录制点后 window 样本
        start_before = 0
        end_before = start_before + window
        df_before = df.iloc[start_before:end_before]

        # 故障后窗口：t_fault 后 window 样本
        start_after = fault_idx
        end_after = min(len(df), fault_idx + window)
        df_fault = df.iloc[start_after:end_after]

        # Step 3: 计算电流幅值变化
        delta_I = {}
        candidate_phases = []
        for ch_key in ["IA", "IB", "IC"]:
            col = channels.get(ch_key)
            if col and col in df_fault.columns:
                mag_before = compute_magnitude_dft(df_before[col])
                mag_after = compute_magnitude_dft(df_fault[col])
                delta = round(mag_after - mag_before, 4)
                delta_I[ch_key] = round(delta, 6)
                if delta and delta > mag_before:  # 阈值可调
                    candidate_phases.append(ch_key)

        # Step 4: 相量分析
        phase_angles = {}
        phase_magnitudes = {}
        for ch_key in ["IA", "IB", "IC"]:
            col = channels.get(ch_key)
            if col and col in df_fault.columns:
                angle = compute_angle_dft(df_fault[col])
                mag = compute_magnitude_dft(df_fault[col])
                phase_angles[ch_key] = round(angle, 3)
                phase_magnitudes[ch_key] = round(mag, 3)

        # Step 5: 只用电流相位进行故障类型判断
        fault_type = FaultType.UNKNOWN
        if len(candidate_phases) == 1:
            fault_type = FaultType.SINGLE_PHASE_GROUND  # 单相接地
        elif len(candidate_phases) == 2:
            p1, p2 = candidate_phases
            diff_angle = abs((phase_angles[p1] - phase_angles[p2] + 180) % 360 - 180)  # 差值归一化到 [0,180]
            if diff_angle > 120:  # 近似反向
                fault_type = FaultType.LL  # 两相短路
        elif len(candidate_phases) == 3:
            fault_type = FaultType.TRIPLE_FAULT  # 三相短路

        # Step 6: 返回结果（所有数值保留6位小数）
        return FaultTypeResult(
            fault_type=fault_type,
            details={
                "fault_start_time": str(t_fault),
                "delta_I": delta_I,
                "candidate_phases": candidate_phases,
                "phase_angles": phase_angles,
                "phase_magnitudes": phase_magnitudes,
            }
        )
